package main

import (
	"bufio"
	"encoding/json"
	"fmt"
	"html/template"
	"io"
	"os"
	"strconv"
)

type yaml struct {
	ApiAddr         string
	DebugApiAddr    string
	TracingEndpoint string
	P2pAddr         string
	SwapEndpoint    string
}

type bat struct {
	StartTitle string
}

type configuration struct {
	ServerNum    int
	NodeNum      int
	BeePath      string
	BatPath      string
	BatTmplPath  string
	YamlTmplPath string
	SwapEndpoint string
}

var conf = read_json()

func main() {
	// flag.Parse()
	// fmt.Print("n=")
	// fmt.Println(n)
	// n:= "10011"
	//按服务器数量循环
	serverLoop(conf.ServerNum)
}

// 按服务器数量循环
func serverLoop(sever_num int) {
	// 生成前删除目录，避免冲突
	rm_dir("./output/")
	os.Mkdir("./output/", 0777)
	for i := 1; i <= sever_num; i++ {
		fmt.Print("server made =")
		fmt.Println(i)
		server_folder_index := get_i_str(i)
		server_folder_path := "./output/server" + server_folder_index

		// 生成 服务器 目录
		err := os.Mkdir(server_folder_path, 0777)
		if err == nil {
			// 按节点数循环
			nodeLoop(i, conf.NodeNum)
		}
	}
}

// 按节点数量循环
func nodeLoop(server_index, n int) {
	for i := 1; i <= n; i++ {

		fmt.Println(i)
		curren_num := 1000 + i
		node_num_str := strconv.Itoa(curren_num)
		node_folder_index := get_i_str(i)
		server_folder_index := get_i_str(server_index)
		server_path := "./output/server" + server_folder_index
		node_folder_path := server_path + "/bee" + node_folder_index

		// 生成 目录
		err := os.Mkdir(node_folder_path, 0777)
		if err == nil {
			// 拷贝 bee.exe 到目标目录
			copy_file(conf.BeePath, node_folder_path+"/bee.exe")
			// 生成 yaml 文件
			make_yaml(server_folder_index, node_num_str, conf.YamlTmplPath, node_folder_path+"/bee.yaml")
			// 生成 bat 文件
			make_bat(node_folder_index, conf.BatTmplPath, node_folder_path+"/start.bat")
		} else {
			panic(err)
		}

	}
}

// 生成当前序号字符串
func get_i_str(num int) string {
	var i_str string
	if num < 10 {
		i_str = "0" + strconv.Itoa(num)
	} else {
		i_str = strconv.Itoa(num)
	}
	return i_str
}

//生成yaml
func make_yaml(server_num_str, node_num_str, tmp_path, target_path string) {

	// 生成 yaml 文件
	t, err := template.ParseFiles(tmp_path)
	if err == nil {
		p2paddr := get_p2paddr(server_num_str, node_num_str)
		p := yaml{
			ApiAddr:         node_num_str + "1",
			DebugApiAddr:    node_num_str + "2",
			TracingEndpoint: node_num_str + "3",
			P2pAddr:         p2paddr,
			SwapEndpoint:    conf.SwapEndpoint,
		}
		yaml_file, err := os.OpenFile(target_path, os.O_CREATE|os.O_WRONLY, 0755)
		if err == nil {
			defer yaml_file.Close()
			t.Execute(yaml_file, p)
		}

	}

}

// 生成 yaml 中 P2pAddr 端口
func get_p2paddr(server_num_str, node_num_str string) string {
	// server_num 1
	// node_num 1
	server_num, _ := strconv.Atoi(server_num_str)
	server_num_str = strconv.Itoa(server_num + 10)
	node_num, _ := strconv.Atoi(node_num_str)
	node_num = node_num - 1000
	node_num_str = strconv.Itoa(node_num)
	if node_num < 10 {
		node_num_str = "0" + node_num_str
	}

	p2paddr := server_num_str + node_num_str + "4"
	// fmt.Println("server_num_str=" + server_num_str)
	// fmt.Println("node_num_str=" + node_num_str)
	// fmt.Println("p2paddr=" + p2paddr)
	return p2paddr
}

//生成bat
func make_bat(str, tmp_path, target_path string) {

	// 生成 bat 文件
	t, err := template.ParseFiles(tmp_path)
	if err == nil {
		p := bat{
			StartTitle: "bee" + str,
		}
		bat_file, err := os.OpenFile(target_path, os.O_CREATE|os.O_WRONLY, 0755)
		if err == nil {
			defer bat_file.Close()
			t.Execute(bat_file, p)
		}

	}

}

func copy_file(src_path string, dst_path string) (written int64, err error) {
	src_file, err := os.Open(src_path)
	if err != nil {
		fmt.Printf("打开源文件错误，错误信息=%v\n", err)
	}
	defer src_file.Close()
	reader := bufio.NewReader(src_file)

	dst_file, err := os.OpenFile(dst_path, os.O_WRONLY|os.O_CREATE, 0777)
	if err != nil {
		fmt.Printf("打开目标文件错误，错误信息=%v\n", err)
		return
	}
	writer := bufio.NewWriter(dst_file)
	defer dst_file.Close()
	return io.Copy(writer, reader)
}

func rm_dir(path_str string) {
	os.RemoveAll(path_str)
}

//读取 json 文件
func read_json() configuration {
	file, _ := os.Open("./conf.json")
	defer file.Close()
	decoder := json.NewDecoder(file)

	conf := configuration{}
	err := decoder.Decode(&conf)
	if err != nil {
		panic(err)
	}

	return conf
}
